package xginplus

import (
	"context"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
)

// 结构转换，将controller返回的数据转换成gin框架所支持的输出形式
// 传入参数f，其格式为：func(*xginplus.Context) *xginplus.Response
//
//	f	处理该方法的函数标识
//	fc	针对此分组下的追加配置项
func Convert(f func(*Context) *Response, fc ...ContextOptionFunc) gin.HandlerFunc {
	return func(c *gin.Context) { // 返回gin.HandlerFunc的无返回值函数（此处直接使用匿名函数进行定义）
		cnt := To(c)
		for _, configure := range fc {
			configure(cnt)
		}
		if cnt.hasJitter() {
			if v, ok := cnt.hasJ(); ok {
				if v == nil {
					return
				}
				if s, ok := v.(string); ok {
					c.String(200, s)
					return
				}
				c.JSON(200, v)
				return
			}
		}
		// 分页处理
		cnt.page_load()
		var resp *Response
		// 超时配置
		if cnt.TimeOut > 0 {
			fmt.Println("超时时间：", cnt.TimeOut, len(fc))
			ctx, cancel := context.WithTimeout(cnt.Context, cnt.TimeOut)
			defer cancel()

			respChan := make(chan *Response, 1)
			go func() {
				respChan <- f(cnt)
			}()

			select {
			case <-ctx.Done():
				resp = cnt.ErrorCf(_default.CodeTimeOut, "请求超时")
			case resp = <-respChan:
			}
		} else {
			resp = f(cnt) // 执行传入的函数，用于获取该返回的返回值
		}

		if resp != nil {
			data := resp.GetData() // 获取Data数据
			cnt.setJ(data)
			switch item := data.(type) { // 根据Data数据进行验证要返回类型
			case string:
				c.String(200, item)
			default:
				c.JSON(200, item)
			}
			return
		}
		cnt.setJ(nil)
	}
}

// 直接推送路由信息到router表中
// 支持使用gin框架支持的路由通配符等，但是不建议使用太多，因为此处不支持使用后缀方法进行追加效验
//
//	r		gin的原生路由分组，用于插入配置的路由信息
//	mp		待推入的路由下标
//	mp.key	路由，使用:分割，第一个参数为请求方式，第二个参数为路由规则。
//			目前支持get(默认)/post/options/head/patch/delete/put/any
//			转化示例如：
//				get:/index => r.GET("/index")
//				get:/index/:abc => r.GET("/index/:abc")
//				post:info/:name => r.POST("/info/:name")
//	mp.val	处理函数
//	fc		针对此分组下的追加配置项
func ConvertMap(r *gin.RouterGroup, mp map[string]func(*Context) *Response, fc ...ContextOptionFunc) {
	for k, v := range mp {
		spl := strings.Split(k, ":")
		if len(spl) == 1 {
			// 没找到:
			r.GET(k, Convert(v, fc...))
			continue
		}
		// 找到了路由规则
		switch strings.ToLower(spl[0]) {
		case "get":
			r.GET(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "post":
			r.POST(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "options":
			r.OPTIONS(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "head":
			r.HEAD(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "patch":
			r.PATCH(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "delete":
			r.DELETE(strings.Join(spl[1:], ":"), Convert(v, fc...))
		case "put":
			r.PUT(strings.Join(spl[1:], ":"), Convert(v, fc...))
		default:
			r.Any(strings.Join(spl[1:], ":"), Convert(v, fc...))
		}
	}
}
